package com.yuantong.xyerp.rest.controller;

import com.yuantong.xyerp.core.api.enums.EnumMsgCode;
import com.yuantong.xyerp.core.api.model.Attachment;
import com.yuantong.xyerp.core.api.model.base.RestResponseModel;
import com.yuantong.xyerp.core.api.service.IAttachmentService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Hex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.List;
import java.util.UUID;
/**
 * @author 金鑫
 */
@Slf4j
@RestController
@RequestMapping("/attachment")
@Api(tags = "附件管理")
public class AttachmentController {
    @Autowired
    private IAttachmentService attachmentService;
    @Value("${attachment.root}")
    private String ATTATCHMENT_ROOT;

    @PostMapping(value = "/upload")
    @ApiOperation(value = "附件上传",httpMethod = "POST",notes = "文件上传到统一的附件区，一个物主可以上传任意多个附件，前端做限制")
    public RestResponseModel<Attachment> upload(@ApiParam("上传的文件") @RequestParam("file") MultipartFile file,
                                                @ApiParam("附件名字（不是文件名）") @RequestParam("name") String name,
                                                @ApiParam("附件从属的对象的UUID")@RequestParam("masterId") String masterId,
                                                @ApiParam("上传人的UUID，可空")@RequestParam(value = "uploaderId",required = false) String uploaderId,
                                                HttpServletResponse response) {
        // response.setHeader("Access-Control-Allow-Origin", "*");
        Attachment attachment=saveFile(file);
        if(attachment==null){
            return RestResponseModel.FAIL(EnumMsgCode.MSG_INVALID_FILEUPLOAD);
        }
        attachment.setUploaderId(uploaderId);
        attachment.setName(name);
        attachment.setMasterId(masterId);
        attachmentService.saveAttachment(attachment);

        return RestResponseModel.SUCCESS(EnumMsgCode.MSG_SUCCESS, attachment);
    }
    @GetMapping("/list/{id}")
    @ApiOperation(value = "获取附件清单",httpMethod = "GET",notes = "根据附件的物主UUID，提取关联的附件集合")
    public RestResponseModel<List<Attachment>> masterAttachments(@ApiParam("附件物主的UUID") @PathVariable("id") String masterId){
        List<Attachment> attachments=attachmentService.getByMasterId(masterId);
        return RestResponseModel.SUCCESS(EnumMsgCode.MSG_SUCCESS, attachments);
    }
    private Attachment saveFile(MultipartFile file){
        Attachment attachment = new Attachment();
        attachment.setId(UUID.randomUUID().toString().replaceAll("-",""));
        attachment.setContentType(file.getContentType());
        String fileName=file.getOriginalFilename();
        attachment.setFileName(fileName);
        int suffixPos = fileName.lastIndexOf('.');
        if (suffixPos > 0) {
            attachment.setSuffix(fileName.substring(suffixPos + 1));
        }
        attachment.setUploadTime(new Timestamp(System.currentTimeMillis()));

        Calendar cal = Calendar.getInstance();
        String yearmonth = cal.get(Calendar.YEAR) + "-" + (cal.get(Calendar.MONTH) + 1);
        File dir = Paths.get(ATTATCHMENT_ROOT, yearmonth).toFile();
        if (!dir.exists()) {
            if (!dir.mkdirs()) {
                log.error("保存上传的附件【{}】时发生错误，目录【{}】无法创建", attachment.getFileName(), dir.getAbsolutePath());
                return null;
            }
        }

        Path filePath = Paths.get(ATTATCHMENT_ROOT, yearmonth, attachment.getId());

        try {
            Files.copy(file.getInputStream(), filePath);

            long fileSize = 0;
            InputStream is1 = Files.newInputStream(filePath);
            byte[] buf = new byte[2048];
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            MessageDigest sha1 = MessageDigest.getInstance("SHA1");

            int len;
            while ((len = is1.read(buf)) != -1) {
                md5.update(buf, 0, len);
                sha1.update(buf, 0, len);
                fileSize += len;
            }
            attachment.setFilePath(filePath.toString());
            attachment.setFileSize(fileSize);
            attachment.setMd5Value(Hex.encodeHexString(md5.digest()));
            attachment.setSha1Value(Hex.encodeHexString(sha1.digest()));
        } catch (IOException | NoSuchAlgorithmException e) {
            log.error("保存上传的附件【{}】时发生错误",attachment.getFileName(), e);
            return null;
        }
        return attachment;
    }

    @GetMapping("/link/{id}")
    @ApiOperation(value = "附件链接",httpMethod = "GET",notes = "通过附件的UUID提供附件的超级链接，供显示或下载")
    public ResponseEntity<Resource> accessAttachment(@ApiParam("附件UUID")@PathVariable(name = "id") String attachmentId) {
        Attachment dto = attachmentService.getById(attachmentId);
        if (dto == null) {
            return ResponseEntity.notFound().build();
        }

        try {
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.parseMediaType(dto.getContentType()));
            headers.setContentDispositionFormData("attachment",
                    new String(dto.getFileName().getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
            headers.setContentLength(dto.getFileSize());

            Path path = Paths.get(dto.getFilePath());
            if (Files.exists(path)) {
                return ResponseEntity.ok().headers(headers).body(new UrlResource(path.toUri()));
            } else {
                return ResponseEntity.notFound().build();
            }
        } catch (MalformedURLException e) {
            log.error("获取附件【{}|{}】失败", dto.getId(), dto.getFileName(), e);
            return ResponseEntity.notFound().build();
        } catch (Exception e) {
            log.error("获取附件【{}|{}】时发生异常", dto.getId(), dto.getFileName(), e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }
    @GetMapping("/{id}")
    @ApiOperation(value = "附件详情",httpMethod = "GET",notes = "通过附件的UUID获取该附件的详情")
    public RestResponseModel<Attachment> attachmentDetail(@ApiParam("附件UUID")@PathVariable("id") String attachmentId){
        Attachment attachment=attachmentService.getById(attachmentId);
        return RestResponseModel.SUCCESS(EnumMsgCode.MSG_SUCCESS, attachment);
    }
    @DeleteMapping("/{id}")
    @ApiOperation(value = "删除附件",httpMethod = "DELETE",notes = "通过附件的UUID删除附件（逻辑删除，对应文件不删除）")
    public RestResponseModel<String> deleteAttachment(@ApiParam("附件UUID")@PathVariable("id") String attachmentId){
        attachmentService.deleteAttachment(attachmentId);
        return RestResponseModel.SUCCESS(EnumMsgCode.MSG_SUCCESS,"成功删除附件："+attachmentId);
    }
}
